ConnectToDB()
{
	bIsConnectedToDB = false;
	if(SQL_hDB != INVALID_HANDLE)
	{
		CloseHandle(SQL_hDB);
		SQL_hDB = INVALID_HANDLE;
	}

	if(SQL_CheckConfig("ncs_rpg"))
		SQL_TConnect(CallBackConnectToDB, "ncs_rpg");
	else if(SQL_CheckConfig("default"))
		SQL_TConnect(CallBackConnectToDB, "default");
	else if(SQL_CheckConfig("storage-local"))
		SQL_TConnect(CallBackConnectToDB, "storage-local");
	else
		LogError("Unable to connect to database, reason: no config entry found for 'ncs_rpg' in databases.cfg");
}

public CallBackConnectToDB(Handle:owner, Handle:hndl, const String:error[], any:data)
{
	if(hndl == INVALID_HANDLE)
	{
		LogError("Unable to connect the database, reason: %s", error);
		ConnectToDB();
		return;
	}

	SQL_hDB = CloneHandle(hndl);
	if(SQL_hDB == INVALID_HANDLE)
	{
		ConnectToDB();
		return;
	}
	bIsConnectedToDB = true;
	LogMessage("Successfully connected to database");
	API_OnDBConnected();
	
	CreateTable();
}

CreateTable()
{
	if(!IsConnectedToDB())
		return;
	
	decl String:query[256];
	Format(query, sizeof(query), "CREATE TABLE IF NOT EXISTS ncs_rpg (steamid VARCHAR(32) NOT NULL PRIMARY KEY, name VARCHAR(%d), level INTEGER(16), xp INTEGER(16), reqxp INTEGER(16), credits INTEGER(16), lastconnect INTEGER(32))", MAX_NAME_LENGTH);
	SQL_TQuery(SQL_hDB, CallBackCreateTable, query, 0, DBPrio_High);
}

public CallBackCreateTable(Handle:owner, Handle:hndl, const String:error[], any:data)
{
	if(hndl == INVALID_HANDLE)
	{
		LogError("Could not create the table, reason: %s", error);
		CreateTable();
		return;
	}
	OnSkillsRegister();
}

LoadPlayer(client)
{
	if(!IsConnectedToDB())
		return;
	
	decl String:query[8192], String:auth[32];
	GetClientAuthString(client, auth, sizeof(auth));
	Format(query, sizeof(query), "SELECT level, xp, reqxp, credits");
	for(new i = 0; i < GetSkillCount(); i++)
		Format(query, sizeof(query), "%s, _%s", query, SkillShortname[i]);
	Format(query, sizeof(query), "%s FROM ncs_rpg WHERE steamid = '%s'", query, auth);
	SQL_TQuery(SQL_hDB, CallBackLoadPlayer, query, client, DBPrio_Normal);
}

public CallBackLoadPlayer(Handle:owner, Handle:hndl, const String:error[], any:client)
{
	if(hndl == INVALID_HANDLE)
	{
		LogError("Unable to load the player, reason: %s", error);
		return;
	}
	
	if(!SQL_FetchRow(hndl))
	{
		InsertPlayerInDB(client);
	}
	else
	{
		SetLevel(client, SQL_FetchInt(hndl, 0));
		SetXP(client, SQL_FetchInt(hndl, 1));
		SetReqXP(client, SQL_FetchInt(hndl, 2));
		SetCredits(client, SQL_FetchInt(hndl, 3));
		new field = 3;
		for(new i = 0; i < GetSkillCount(); i++)
			SetSkillLevel(client, i, SQL_FetchInt(hndl, ++field));
		
		ClientLoaded[client] = true;
		API_OnClientLoaded(client);
	}
}

InsertPlayerInDB(client)
{
	decl String:query[8192], String:name[MAX_NAME_LENGTH], String:auth[32];
	GetClientAuthString(client, auth, sizeof(auth));
	GetClientName(client, name, sizeof(name));
	ReplaceString(name, sizeof(name), "'", "", false);
	
	Format(query, sizeof(query), "INSERT INTO ncs_rpg (steamid, name, level, xp, reqxp, credits, lastconnect");
	for(new i = 0; i < GetSkillCount(); i++)
		Format(query, sizeof(query), "%s, _%s", query, SkillShortname[i]);
	
	Format(query, sizeof(query), "%s) VALUES ('%s', '%s', '%i', '%i', '%i', '%i', '%i'", query, auth, name, SetLevel(client, 1), SetXP(client, 0), SetReqXP(client, GetConfigValue("xp", "exp_start")), GetConfigValue("xp", "credits_start"), GetTime());
	
	for(new i = 0; i < GetSkillCount(); i++)
		Format(query, sizeof(query), "%s, %i", query, 0);
	
	Format(query, sizeof(query), "%s)", query);
	SQL_TQuery(SQL_hDB, CallBackInsertPlayer, query, client, DBPrio_Normal);
}

public CallBackInsertPlayer(Handle:owner, Handle:hndl, const String:error[], any:client)
{
	if(hndl == INVALID_HANDLE)
	{
		LogError("Unable to create the player, reason: %s", error);
		return;
	}
	
	ResetVariables(client);
	ClientLoaded[client] = true;
	API_OnClientLoaded(client);
}

SavePlayer(client)
{
	if(!IsClientLoaded(client) || !IsConnectedToDB())
		return;
	
	decl String:query[8192], String:auth[32];
	GetClientAuthString(client, auth, sizeof(auth));
	GetClientName(client, query, sizeof(query));
	ReplaceString(query, sizeof(query), "'", "");
	Format(query, sizeof(query), "name = '%s', level = '%i', xp = '%i', reqxp = '%i', credits = '%i', lastconnect = '%i'", query, GetLevel(client), GetXP(client), GetReqXP(client), GetCredits(client), GetTime());
	for(new i = 0; i < GetSkillCount(); i++)
		Format(query, sizeof(query), "%s, _%s = '%i'", query, SkillShortname[i], GetSkillLevel(client, i));
	
	Format(query, sizeof(query), "UPDATE ncs_rpg SET %s WHERE steamid = '%s'", query, auth);
	SQL_TQuery(SQL_hDB, CallBackSavePlayer, query, client, DBPrio_Normal);
}

public CallBackSavePlayer(Handle:owner, Handle:hndl, const String:error[], any:data)
{
	if(hndl == INVALID_HANDLE)
	{
		LogError("Unable to update the player, reason: %s", error);
		return;
	}
}

CreateColumn(const String:columname[], const String:settings[])
{
	if(!IsConnectedToDB())
		return;
	
	decl String:query[1024];
	Format(query, sizeof(query), "SELECT %s FROM ncs_rpg LIMIT 1", columname);
	if(!SQL_FastQuery(SQL_hDB, query))
	{
		Format(query, sizeof(query), "ALTER TABLE ncs_rpg ADD COLUMN %s %s", columname, settings);
		if(SQL_FastQuery(SQL_hDB, query))
			LogMessage("Successfully created column: %s [%s]", columname, settings);
		else
		{
			SQL_GetError(SQL_hDB, query, sizeof(query));
			LogError("Could not create column %s [%s], reason: %s", columname, settings, query);
		}
	}
}

ResetPlayer(client)
{
	if(!IsValidPlayer(client))
	{
		#if DEBUG
			LogError("Unable to reset the player, reason: invalid client %i", client);
		#endif
		return;
	}
	
	new count = GetSkillCount();
	decl String:buffer[128], level[count];
	
	new Handle:datapack = CreateDataPack();
	WritePackCell(datapack, client);
	
	for(new i = 0; i < GetSkillCount(); i++)
	{
		level[i] = GetSkillLevel(client, i);
		WritePackCell(datapack, level[i]);
		OnSkillUP(client, i, level[i], 0);
	}
	
	GetClientAuthString(client, buffer, sizeof(buffer));
	Format(buffer, sizeof(buffer), "DELETE FROM ncs_rpg WHERE steamid = '%s'", buffer);
	SQL_TQuery(SQL_hDB, CallBackResetPlayer, buffer, datapack, DBPrio_High);
}

public CallBackResetPlayer(Handle:owner, Handle:hndl, const String:error[], any:datapack)
{
	ResetPack(datapack);
	new client = ReadPackCell(datapack);
	if(hndl == INVALID_HANDLE)
	{
		LogError("Unable to reset the player, reason: %s", error);
		for(new i = 0; i < GetSkillCount(); i++)
			OnSkillUP(client, i, 0, ReadPackCell(datapack));
		
		return;
	}
	ResetVariables(client);
	InsertPlayerInDB(client);
	
	#if DEBUG
		LogMessage("Player '%N' (%i) successfully reset", client, client);
	#endif
}